<template>
  <div class="app-root-container">
    <el-container>
      <el-header height="50px">应用管理</el-header>
      <el-container>
        <el-aside width="200px">
          <div class="app-header">
            <span>所有应用</span>
            <i class="tempo-td-icon el-icon-plus"
               @click="createApp"></i>
          </div>
          <div class="app-container">
            <el-input size="mini"
                      placeholder="请输入内容"
                      v-model="appNameFilter"
                      clearable
                      prefix-icon="el-icon-search">
            </el-input>
            <ul class="app-list">
              <li v-for="(item, index) in filtedApps"
                  :key="item.id"
                  @mouseover="selectStyle (item) "
                  @mouseout="outStyle(item)"
                  @click="selectApp(item)"
                  class="app-item"
                  :class="{'active':item.active, 'selected': item.selected}">
                {{ item.name }}

                <i v-show="item.active"
                   class="tempo-td-icon app-item-icon el-icon-edit"
                   @click="editApp(item)"></i>
                <i v-show="item.active"
                   class="tempo-td-icon app-item-icon el-icon-delete"
                   @click="deleteApp(item.id)"></i>
              </li>

            </ul>
          </div>
        </el-aside>
        <el-main direction="horizontal">
          <template v-if="selectedApp">
            <p class="app-cert-info">
              <span class="primary-title">APPKey:</span>
              <span class="primary-info">{{selectedApp.key}}</span>
              <span class="primary-title">APPSecret:</span>
              <span class="primary-info">{{selectedApp.secret}}</span>
              <span class="primary-title">证书:</span>
              <a :href="'http://localhost:8089/application/credential/' + selectedApp.id"
                 target="_blank"
                 type="primary">下载</a>

            </p>
            <div class="app-table-toolbar">
              <el-button size="small"
                         icon="el-icon-plus"
                         @click="bindServices"
                         type="primary">绑定服务</el-button>
              <el-button size="small"
                         icon="el-icon-delete"
                         @click="batchCancelService"
                         type="danger">取消绑定</el-button>

            </div>
            <el-table :data="dataServices"
                      row-key="sid"
                      @selection-change="handleSelectionChange"
                      height="500">
              <el-table-column type="selection"
                               width="55">
              </el-table-column>
              <el-table-column prop="name"
                               label="名称"
                               width="140">
              </el-table-column>
              <el-table-column prop="categroy"
                               label="分组"
                               width="120">
              </el-table-column>
              <el-table-column prop="description"
                               label="描述">
              </el-table-column>
              <el-table-column prop="state"
                               label="状态">
              </el-table-column>
              <el-table-column prop="impl_type"
                               label="类型"
                               width="120">
              </el-table-column>
              <el-table-column prop="creator"
                               label="创建人">
              </el-table-column>
              <el-table-column prop=""
                               width="50"
                               label="操作">
                <template slot-scope="scope">
                  <el-button icon="el-icon-delete"
                             @click.native.prevent="deleteRow(scope.$index, scope.row, dataServices)"
                             type="text"
                             size="small">
                  </el-button>
                </template>
              </el-table-column>
            </el-table>

          </template>
          <template v-else>
            <el-container>
              <el-main style="color : #797777">
                请点击右侧新建一个应用或者选择已有的应用打开
              </el-main>
            </el-container>
          </template>
        </el-main>
      </el-container>
    </el-container>

    <el-dialog title="绑定服务"
               :close-on-click-modal="false"
               :visible.sync="bindServicesDialogVisible"
               width="30%">
      <el-input placeholder="服务名称"
                v-model="servicefilterText">
      </el-input>

      <el-tree class="filter-tree"
               :data="serviceTree"
               :props="serviceProps"
               :show-checkbox="true"
               node-key="id"
               default-expand-all
               :filter-node-method="filterService"
               ref="tree">
      </el-tree>
      <span slot="footer"
            class="dialog-footer">
        <el-button @click="bindServicesDialogVisible = false">取 消</el-button>
        <el-button type="primary"
                   @click="saveAppServices">确 定</el-button>
      </span>
    </el-dialog>

    <el-dialog :title="appDialogTitleMapping[appDialogStatus]"
               @close="onClose"
               :close-on-click-modal="false"
               :visible.sync="createAppDialogVisible"
               width="50%">

      <el-form ref="appCreateForm"
               :model="appRecord"
               :rules="rules"
               size="medium"
               label-width="120px">
        <el-form-item label="应用名称"
                      prop="name">
          <el-input v-model="appRecord.name"
                    placeholder="请输入应用名称"
                    clearable
                    maxlength="60"
                    show-word-limit
                    :style="{width: '100%'}">
          </el-input>
        </el-form-item>
        <el-form-item label="描述"
                      prop="desc">
          <el-input v-model="appRecord.desc"
                    type="textarea"
                    maxlength="500"
                    resize="none"
                    placeholder="请输入描述"
                    :autosize="{minRows: 4, maxRows: 4}"
                    :style="{width: '100%'}"></el-input>
        </el-form-item>
        <el-form-item label="授权证书"
                      ref="credentialItem"
                      prop="credential">
          <el-upload ref="credential"
                     :before-upload="beforeupload"
                     :auto-upload="false"
                     :file-list="credentialFile"
                     :on-change="credentialChange"
                     action="">
            <el-button size="small"
                       type="primary"
                       icon="el-icon-upload">点击上传</el-button>
          </el-upload>
        </el-form-item>

        <el-form-item label="时长"
                      prop="duration">
          <el-row>
            <el-col :span="6">
              <el-input-number v-model="appRecord.duration"
                               controls-position="right"
                               :style="{width: '100%'}"
                               :min="1"></el-input-number>
            </el-col>
            <el-col :offset="1"
                    :span="6">
              <el-select v-model="appRecord.durationUnit"
                         placeholder="选择分钟/小时/天"
                         clearable>
                <el-option v-for="(item, index) in durationUnitOptions"
                           :key="index"
                           :label="item.label"
                           :value="item.value"
                           :disabled="item.disabled"></el-option>
              </el-select>

            </el-col>
          </el-row>
        </el-form-item>

        <el-form-item label="API限流次数"
                      prop="apiLimit">
          <el-row>
            <el-col :span="6">
              <el-input-number v-model="appRecord.apiLimit"
                               placeholder="API限流次数"
                               :min="1"
                               :style="{width: '100%'}"
                               controls-position=right>
              </el-input-number>
            </el-col>
          </el-row>
        </el-form-item>
      </el-form>

      <span slot="footer"
            class="dialog-footer">
        <el-button @click="createAppDialogVisible = false">取 消</el-button>
        <el-button type="primary"
                   @click="saveApp('appCreateForm')">确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>
<script>
import axios_ from 'axios'

/**
 * 
 * axios实例，全局的请求头content-type被重置了，在文件上传的时候需要特殊修改一下
 */
const appSevice = axios_.create({
  timeout: 20 * 1000
});
export default {
  data () {
    return {
      //应用绑定的服务列表
      dataServices: [],
      //所有的应用列表
      apps: [],
      //应用搜索条件
      appNameFilter: '',
      //应用创建对话框显示状态
      createAppDialogVisible: false,
      //应用对话框状态
      appDialogStatus: 'new',
      appDialogTitleMapping: {
        'new': '新增应用',
        'edit': '编辑应用'
      },
      //应用默认值
      appRecord: {},
      //选中的应用
      selectedApp: null,
      formData: null,
      credentialFile: [],
      //创建应用表单验证规则
      rules: {
        name: [{
          required: true,
          message: '请输入应用名称',
          trigger: 'blur'
        }],
        duration: [{
          required: true,
          message: '请输入时长',
          trigger: 'blur'
        }],
        durationUnit: [{
          required: true,
          message: '选择分钟/小时/天',
          trigger: 'change'
        }],
        apiLimit: [{
          required: true,
          message: 'API限流次数',
          trigger: 'blur'
        }],
        credential: [{
          required: true,
          message: '请选择授权证书',
          trigger: 'change',
          validator: this.validateCredentialFile
        }]
      },
      durationUnitOptions: [{
        "label": "分钟",
        "value": 1
      }, {
        "label": "小时",
        "value": 2
      }, {
        "label": "天",
        "value": 3
      }],
      bindServicesDialogVisible: false,
      servicefilterText: '',
      serviceTree: [],
      serviceProps: {
        children: 'apis',
        label: 'name'
      },
      //服务列表选中记录
      multipleSelection: [],
    }
  },

  created: function () {
    //页面加载后请求应用列表
    this.loadApp();
  },
  watch: {
    servicefilterText (val) {
      this.$refs.tree.filter(val);
    }
  },
  computed: {
    /**
     * 根据应用筛选过滤应用，以在列表中显示
     */
    filtedApps: function () {
      let that = this;
      return this.apps.filter(function (app) {
        return app.name.toLowerCase().indexOf(that.appNameFilter) != -1
      })
    }
  },
  methods: {
    /**
     * 加载所有应用
     */
    loadApp () {
      this.axios.get(this.HOST + "/application/list").then(response => (this.apps = response.data))
    },
    /**
     * 新建按钮处理
     */
    createApp () {
      this.appRecord = {
        name: undefined,
        desc: undefined,
        credential: null,
        duration: 1,
        durationUnit: 3,
        apiLimit: 5,
      }
      this.appDialogStatus = 'new';
      this.createAppDialogVisible = true;
    },
    /**
    * 新建按钮处理
    */
    editApp (item) {
      this.appDialogStatus = 'edit';
      this.createAppDialogVisible = true;
      this.appRecord = item;
      this.credentialFile.splice(0)
      this.credentialFile.push({
        name: item.credentialName,
        url: 'http://localhost:8089/application/credential/' + item.id
      })
    },
    /**
     * 选中一个应用
     */
    selectApp (item) {
      this.selectedApp = item;
      let that = this;
      this.apps.forEach(function (item) {
        that.$set(item, 'selected', false);
      });
      this.$set(item, 'selected', true);
      this.loadAppService()
    },

    loadAppService () {
      this.axios.get(this.HOST + "application/services/" + this.selectedApp.id).then(response => (this.dataServices = response.data))
    },

    /**
     * 删除应用
     */
    deleteApp (id) {
      let that = this;
      this.$confirm('确定删除应用?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        this.axios.post(this.HOST + '/application/delete?id=' + id).then(function (result) {
          that.selectedApp = null;
          that.loadApp()
          that.$message({
            type: 'success',
            message: '删除成功!'
          });
        })
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        });
      });
    },


    /**
     * 保存应用
     */
    saveApp (formName) {
      let that = this
      this.$refs[formName].validate((valid) => {
        if (valid) {
          that.createAppDialogVisible = false;
          that.$refs.credential.submit();
          Object.keys(that.appRecord).forEach((key) => {
            that.formData.append(key, that.appRecord[key]);
          });
          let config = {
            headers: {
              'Content-Type': 'multipart/form-data'
            }
          }
          let url = '/application/save';
          if (that.appDialogStatus == 'edit') {
            that.formData.delete('credential');
            url = '/application/update'
          }
          appSevice.post(that.HOST + url, that.formData, config).then(function (result) {
            that.loadApp()
          })
        } else {
          return false;
        }
      });
    },
    /**
     * 文件上传之前处理
     */
    beforeupload (file) {
      this.formData = new FormData()
      this.formData.append('file', file)
      return false
    },
    /**
     * 文件发生变化时
     */
    credentialChange (file, fileList) {
      if (fileList.length && fileList.length >= 1) {
        this.$refs['credentialItem'].clearValidate();
      }
    },
    /**
     * 授权证书校验
     */
    validateCredentialFile: function (rule, value, callback) {
      if (!this.$refs.credential.uploadFiles.length) {
        callback(new Error('请选择要上传的文件'));
      } else {
        callback();
      }
    },
    /**
   * 服务列表删除行操作
   */
    deleteRow (index, row, rows) {
      debugger;
      this.$confirm('确定删除已经绑定的服务?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        this.axios.post(this.HOST + "/application/unbindservice/" + row.sid).then(function (res) {
          rows.splice(index, 1);
          this.$message({
            type: 'success',
            message: '删除成功!'
          });
        })
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        });
      });
    },
    /**
     * form dialog关闭后重置表单
     */
    onClose () {
      this.$refs['appCreateForm'].resetFields()
    },

    /**
     * 绑定服务
     */
    bindServices () {
      let that = this;
      this.axios.get(this.HOST + "/apicategory/tree").then(function (response) {
        that.serviceTree = response.data.data;
        that.serviceTree.forEach(item => item.id += "category");
        that.$refs.tree.setCheckedKeys(that.dataServices.map(obj => obj.id));
      })
      this.bindServicesDialogVisible = true;
    },
    /**
     * 服务筛选
     */
    filterService (value, data) {
      if (!value) return true;
      return data.name.indexOf(value) !== -1;
    },

    saveAppServices () {
      let checked = this.$refs.tree.getCheckedNodes(true);
      let serviceIds = []
      checked.forEach(function (item, index) {
        serviceIds.push(item.id);
      })
      let that = this;
      this.axios.post(this.HOST + '/application/bindservices/' + this.selectedApp.id,

        { services: serviceIds.join('_') }

      ).then(function (result) {
        that.loadAppService();
      })
      this.bindServicesDialogVisible = false;
    },


    /**
     * 服务列表选中后，更新选中的值
     */
    handleSelectionChange (val) {
      this.multipleSelection = val;
    },
    /**
     * 批量删除服务
     */
    batchCancelService () {
      let that = this;
      if (this.multipleSelection.length == 0) {
        this.$message({
          message: '请至少选择一条服务进行解绑操作',
          type: 'warning'
        });
        return;
      }
      this.$confirm('确定从当前应用中解除选择的服务?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        that.axios.post(that.HOST + '/application/unbindservice',
          {
            services: that.multipleSelection.map(obj => obj.sid).join('_')
          }
        ).then(function (result) {
          that.dataServices = that.dataServices.filter(function (service) {
            return that.multipleSelection.indexOf(service) == -1;
          });
          that.$message({
            type: 'success',
            message: '删除成功!'
          });
        });
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        });
      });
    },
    /**
     * 应用列表当鼠标选中后的处理
     */
    selectStyle (item) {
      let that = this;
      this.$nextTick(function () {
        this.apps.forEach(function (item) {
          that.$set(item, 'active', false);
        });
        this.$set(item, 'active', true);
      });
    },
    /**
     * 应用列表当鼠标离开后的处理
     */
    outStyle (item) {
      this.$set(item, 'active', false);
    }
  }
};
</script>


<style>
.app-root-container {
  height: 100%;
  width: 100%;
  font-size: 14px;
}
.el-container {
  height: 100%;
}
.el-header {
  background-color: #b3c0d1;
  color: #333;
  line-height: 50px;
  height: 50px;
}

.el-aside {
  background-color: #ffffff;
  line-height: 40px;
  height: 40px;
  border: 1px solid #ebebeb;
  height: 100%;
}

.app-header {
  position: relative;
  padding: 0 10px;
  background-color: #eaf4fe;
}

.app-header .el-icon-plus {
  position: absolute;
  right: 10px;
  top: 14px;
}

.app-container {
  padding: 5px;
}

.app-list {
  list-style: none;
  margin: 0;
  padding: 0;
  position: relative;
}
.app-item.active {
  background-color: #d9ecff;
}
.app-item.selected {
  background-color: #96c7f8;
}
.app-item {
  padding: 0 5px;
}
.app-item .app-item-icon {
  line-height: 40px;
  height: 40px;
  position: absolute;
  right: 5px;
}

.app-item .el-icon-edit {
  right: 25px;
}
.app-cert-info {
  font-size: 14px;
  padding: 0;
  margin: 0;
}
.app-cert-info .primary-info {
  color: #606266;
  font-style: italic;
  margin-right: 20px;
}

.app-cert-info .primary-title {
  font-weight: bold;
  margin-right: 5px;
}
.app-table-toolbar {
  margin-top: 10px;
}
.el-dialog {
  font-size: 12px;
}
.el-upload__tip {
  line-height: 1.2;
}
.filter-tree {
  height: 200px;
  overflow: auto;
}
</style>